/**
 * @file hdl_uart.c
 * @brief USART驱动
 * @author Dream Shao (1090820065@qq.com)
 * @version 1.0
 * @date 2025-07-19
 * 
 * @copyright Copyright (c) 2025
 * 
 * @par 修改日志:
 * Date       Version    Author       Description
 * 2025-07-19     1.0    Dream Shao   初始化配置UART 
 */
#include <string.h>
#include "gd32f4xx_gpio.h"
#include "gd32f4xx_usart.h"

#include "hdl_uart.h"

/*******************************************************************************
 * Definitions
 ******************************************************************************/

/*******************************************************************************
 * Variables
 ******************************************************************************/

 /******************************************************************************
 * Code
 ******************************************************************************/
/**
 * @brief tx/rx IO初始化
 * @param cfg: IO配置
 * @return 成功返回pdPASS，失败返回pdFAIL
 */
static BaseType_t vHdl_IO_Init(HDL_USART_CFG* cfg)
{
    if(cfg == NULL)
    {
        return pdFAIL;
    }
    /*复用设置*/
    gpio_af_set(cfg->tx_cfg.gpio_periph, cfg->tx_cfg.alt_func_num, cfg->tx_cfg.pin);
    gpio_af_set(cfg->rx_cfg.gpio_periph, cfg->rx_cfg.alt_func_num, cfg->rx_cfg.pin);
    /*tx模式设置*/
    gpio_mode_set(cfg->tx_cfg.gpio_periph, GPIO_MODE_AF, GPIO_PUPD_PULLUP, cfg->tx_cfg.pin);
    gpio_output_options_set(cfg->tx_cfg.gpio_periph, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, cfg->tx_cfg.pin);
    /*rx模式设置*/
    gpio_mode_set(cfg->rx_cfg.gpio_periph, GPIO_MODE_AF, GPIO_PUPD_PULLUP, cfg->rx_cfg.pin);
    gpio_output_options_set(cfg->rx_cfg.gpio_periph, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, cfg->rx_cfg.pin);
    return pdPASS;
}

static BaseType_t vHdl_UartIrq_Cfg(HDL_USART_CFG* cfg)
{
    if(cfg == NULL)
    {
        return pdFAIL;
    }
    /*NVIC中断配置*/
    vBoard_IRQ_Config(cfg->tx_irq_type, cfg->tx_irq_priority);
    vBoard_IRQ_Config(cfg->rx_irq_type, cfg->rx_irq_priority);
    return pdPASS;
}
/**
 * @brief DMA配置
 * @param  cfg 
 * @return  成功返回pdPASS，失败返回pdFAIL 
 */
static BaseType_t vHdl_UartDMA_Cfg(HDL_USART_CFG* cfg)
{
    dma_single_data_parameter_struct dma_init_struct;

    if(cfg == NULL)
    {
        return pdFAIL;
    }
    /*tx DMA配置*/
    dma_single_data_para_struct_init(&dma_init_struct);
    dma_deinit(cfg->tx_dma_periph, cfg->tx_channelx);

    dma_init_struct.direction           = DMA_MEMORY_TO_PERIPH;
    dma_init_struct.memory0_addr        = (uint32_t)(cfg->txbuffer);
    dma_init_struct.memory_inc          = DMA_MEMORY_INCREASE_ENABLE;
    dma_init_struct.periph_memory_width = DMA_PERIPH_WIDTH_8BIT;
    dma_init_struct.number              = cfg->txbuf_len;
    dma_init_struct.periph_addr         = (uint32_t)&USART_DATA(cfg->usart_periph);
    dma_init_struct.periph_inc          = DMA_PERIPH_INCREASE_DISABLE;
    dma_init_struct.priority            = DMA_PRIORITY_ULTRA_HIGH;
    dma_single_data_mode_init(cfg->tx_dma_periph, cfg->tx_channelx, &dma_init_struct);
    /*DMA通道外设请求设置*/
    dma_circulation_disable(cfg->tx_dma_periph, cfg->tx_channelx);
    dma_channel_subperipheral_select(cfg->tx_dma_periph, cfg->tx_channelx, cfg->tx_sub_periph);
    /*配置外设中断触发条件*/
    dma_interrupt_flag_clear(cfg->tx_dma_periph, cfg->tx_channelx, DMA_CHXCTL_FTFIE);
    dma_interrupt_disable(cfg->tx_dma_periph, cfg->tx_channelx, DMA_CHXCTL_FTFIE);
    /*使能DMA发送通道*/
    dma_channel_enable(cfg->tx_dma_periph, cfg->tx_channelx);
    /*关闭DMA串口发送*/
    usart_dma_transmit_config(cfg->usart_periph, USART_TRANSMIT_DMA_DISABLE);

    /*rx DMA配置*/
    dma_single_data_para_struct_init(&dma_init_struct);
    dma_deinit(cfg->rx_dma_periph, cfg->rx_channelx);

    dma_init_struct.direction           = DMA_PERIPH_TO_MEMORY;
    dma_init_struct.memory0_addr        = (uint32_t)(cfg->rxbuffer);
    dma_init_struct.memory_inc          = DMA_MEMORY_INCREASE_ENABLE;
    dma_init_struct.periph_memory_width = DMA_PERIPH_WIDTH_8BIT;
    dma_init_struct.number              = cfg->rxbuf_len;
    dma_init_struct.periph_addr         = (uint32_t)&USART_DATA(cfg->usart_periph);
    dma_init_struct.periph_inc          = DMA_PERIPH_INCREASE_DISABLE;
    dma_init_struct.priority            = DMA_PRIORITY_ULTRA_HIGH;
    dma_single_data_mode_init(cfg->rx_dma_periph, cfg->rx_channelx, &dma_init_struct);
    /*DMA通道外设请求设置*/
    dma_circulation_disable(cfg->rx_dma_periph, cfg->rx_channelx);
    dma_channel_subperipheral_select(cfg->rx_dma_periph, cfg->rx_channelx, cfg->rx_sub_periph);
    /*使能DMA接收通道*/
    dma_channel_enable(cfg->rx_dma_periph, cfg->rx_channelx);
    /*打开DMA串口接收*/
    usart_dma_receive_config(cfg->usart_periph, USART_RECEIVE_DMA_ENABLE);
    return pdPASS;
}
 /**
 * @brief USART初始化
 * @param cfg: USART配置
 * @return 成功返回pdPASS，失败返回pdFAIL
 */
BaseType_t vHdl_UartInit(HDL_USART_CFG* cfg)
{
    BaseType_t sta = pdPASS;
    
    if(cfg == NULL)
    {
        return pdFAIL;
    }
    cfg->TxMutex = xSemaphoreCreateMutex();
	if(cfg->TxMutex == NULL){
		return pdFAIL;
	}
    cfg->RxSem = xSemaphoreCreateBinary();
    if(cfg->RxSem == NULL){
		return pdFAIL;
	}
    cfg->TxSem = xSemaphoreCreateBinary();
    if(cfg->TxSem == NULL){
		return pdFAIL;
	}
    /*IO初始化*/
    sta = vHdl_IO_Init(cfg);
    if(sta == pdFAIL)
    {
        return pdFAIL;
    }
    /*NVIC中断配置*/
    sta = vHdl_UartIrq_Cfg(cfg);
    if(sta == pdFAIL)
    {
        return pdFAIL;
    }
    /*USART初始化*/
    usart_deinit(cfg->usart_periph);
    usart_baudrate_set(cfg->usart_periph, cfg->baudval);
    usart_data_first_config(cfg->usart_periph, cfg->msbf);
    usart_stop_bit_set(cfg->usart_periph, USART_STB_1BIT);
    usart_word_length_set(cfg->usart_periph, USART_WL_8BIT);
    usart_parity_config(cfg->usart_periph, USART_PM_NONE);
    /*USART收发使能*/
    usart_transmit_config(cfg->usart_periph, USART_TRANSMIT_ENABLE);
    usart_receive_config(cfg->usart_periph, USART_RECEIVE_ENABLE);

    /*发送完成/接收数据缓存区不为空，标志位清除*/
    usart_flag_clear(cfg->usart_periph, USART_FLAG_TC);
    usart_flag_clear(cfg->usart_periph, USART_FLAG_RBNE);
    /*使能串口空闲中断*/
    usart_interrupt_enable(cfg->usart_periph, USART_INT_IDLE);
    // usart_interrupt_enable(cfg->usart_periph, USART_INT_RBNE);

    sta = vHdl_UartDMA_Cfg(cfg);
    if(sta == pdFAIL)
    {
        return pdFAIL;
    }
    /*USART使能*/
    usart_enable(cfg->usart_periph);
    return pdPASS;
}
/**
 * @brief USART发送数据
 * @param  cfg   : USART配置
 * @param  data  : 待发送数据
 * @param  len   : 待发送数据长度
 */
void vHdl_Uart_PollingWrite(HDL_USART_CFG* cfg, uint8_t* data, uint32_t len )
{

    if(cfg == NULL || data == NULL)
    {
        return;
    }
    for(uint32_t i = 0; i < len; i++)
    {
        usart_data_transmit(cfg->usart_periph, data[i]);
        while(RESET == usart_flag_get(cfg->usart_periph, USART_FLAG_TC));
    }
    
}
/**
 * @brief USART DMA发送数据
 * @param  cfg   : USART配置
 * @param  data  : 待发送数据
 * @param  len   : 待发送数据长度
 */
BaseType_t vHdl_Uart_DMAWrite(HDL_USART_CFG* cfg, uint8_t* data, uint32_t len)
{
    if(cfg == NULL || data == NULL)
    {
        return pdFAIL;
    }
    if (xSemaphoreTake(cfg->TxMutex, portMAX_DELAY) != pdTRUE){//形参为一直等待，只能一直阻塞在这，不会到if中
		return pdFAIL;
	}
    if(len > cfg->txbuf_len)
    {
        len = cfg->txbuf_len;
    }
    memcpy(cfg->txbuffer, (const uint8_t*)data, len);
    /*DMA发送关闭*/
    dma_interrupt_flag_clear(cfg->tx_dma_periph, cfg->tx_channelx,DMA_INT_FLAG_FTF);
    dma_channel_disable(cfg->tx_dma_periph, cfg->tx_channelx);
    usart_dma_transmit_config(cfg->usart_periph, USART_TRANSMIT_DMA_DISABLE);
    dma_interrupt_flag_clear(cfg->tx_dma_periph, cfg->tx_channelx,DMA_INT_FLAG_FTF);

    dma_memory_address_config(cfg->tx_dma_periph, cfg->tx_channelx, DMA_MEMORY_0, (uint32_t)(cfg->txbuffer));
    dma_transfer_number_config(cfg->tx_dma_periph, cfg->tx_channelx,len);

    dma_interrupt_enable(cfg->tx_dma_periph, cfg->tx_channelx, DMA_CHXCTL_FTFIE);
    dma_channel_enable(cfg->tx_dma_periph, cfg->tx_channelx);
    usart_dma_transmit_config(cfg->usart_periph, USART_TRANSMIT_DMA_ENABLE);
    /*获取信号量,获取到之后代表发送进程结束，可以释放互斥量*/
	(void)xSemaphoreTake(cfg->TxSem, portMAX_DELAY);
	/* Unlock resource mutex */
	(void)xSemaphoreGive(cfg->TxMutex);
    return pdPASS;
}
